/*******************************************************
* drv_l2_usbd_uvc.c
*
* Purpose: USBD video class driver
*
*
* Author: Eugene Hsu
*
* Date: 2012/04/02
*
* Copyright Generalplus Corp. ALL RIGHTS RESERVED.
*
* Version :
* History :
*
*******************************************************/

/*******************************************************
    Include file
*******************************************************/
#include <string.h>
#include "drv_l1_usbd.h"
#include "drv_l2_usbd.h"
#include "drv_l2_usbd_uvc_uc.h"

/******************************************************
    Definitions and variable declaration
*******************************************************/

/******************************************************
*	Extern variables and functions
******************************************************/
/******************************************************
*	Variables declaration
******************************************************/
extern USBD_CONTROL ctl_ctlblk;
extern INT8U USB_UVC_MJPEG_ConfigDescriptor[];
static INT8U UVC_PowerMode          = 0xA0;				/* Power Mode */
static INT8U UVC_ErrorCode          = NO_ERROR_ERR;   	/* Error Code */

#if (UVC_PU_CONTROL_BM & PU_BM_BRIGHTNESS)
static INT16 UVC_puBrightnessCur    = 0x0010; /* ProcessingUnit Brightness Current */
static INT16 UVC_puBrightnessDef    = 0x0010; /* ProcessingUnit Brightness Default */
static INT16 UVC_puBrightnessMin    = 0x0001; /* ProcessingUnit Brightness Minimum */
static INT16 UVC_puBrightnessMax    = 0x00FF; /* ProcessingUnit Brightness Maximum */
static INT16 UVC_puBrightnessRes    = 0x0001; /* ProcessingUnit Brightness Resolution */
#endif

#if (UVC_PU_CONTROL_BM & PU_BM_HUE)
static SINT16 UVC_puHueCur    = 16; 		/* ProcessingUnit Hue Current */
static SINT16 UVC_puHueDef    = 16; 		/* ProcessingUnit Hue Default */
static SINT16 UVC_puHueMin    = -128;		/* ProcessingUnit Hue Minimum */
static SINT16 UVC_puHueMax    = 127; 		/* ProcessingUnit Hue Maximum */
static SINT16 UVC_puHueRes    = 0x0001; 	/* ProcessingUnit Hue Resolution */
#endif

#if (UVC_PU_CONTROL_BM & PU_CONTRAST_CONTROL)
static INT16 UVC_puContrastCur    = 16; 	/* ProcessingUnit Contrast Current */
static INT16 UVC_puContrastDef    = 16; 	/* ProcessingUnit Contrast Default */
static INT16 UVC_puContrastMin    = 1; 		/* ProcessingUnit Contrast Minimum */
static INT16 UVC_puContrastMax    = 255; 	/* ProcessingUnit Contrast Maximum */
static INT16 UVC_puContrastRes    = 0x0001; /* ProcessingUnit Contrast Resolution */
#endif

#if (UVC_PU_CONTROL_BM & PU_BM_SATURATION)
static INT16 UVC_puSaturationCur    = 16; 		/* ProcessingUnit Saturation Current */
static INT16 UVC_puSaturationDef    = 16; 		/* ProcessingUnit Saturation Default */
static INT16 UVC_puSaturationMin    = 1; 		/* ProcessingUnit Saturation Minimum */
static INT16 UVC_puSaturationMax    = 255; 		/* ProcessingUnit Saturation Maximum */
static INT16 UVC_puSaturationRes    = 0x0001; 	/* ProcessingUnit Saturation Resolution */
#endif

#if (UVC_PU_CONTROL_BM & PU_BM_SHARPNESS)
static INT16 UVC_puSharpnessCur    = 3; 		/* ProcessingUnit Sharpness Current */
static INT16 UVC_puSharpnessDef    = 2; 		/* ProcessingUnit Sharpness Default */
static INT16 UVC_puSharpnessMin    = 0; 		/* ProcessingUnit Sharpness Minimum */
static INT16 UVC_puSharpnessMax    = 3; 		/* ProcessingUnit Sharpness Maximum */
static INT16 UVC_puSharpnessRes    = 0x0001; 	/* ProcessingUnit Sharpness Resolution */
#endif

#if (UVC_PU_CONTROL_BM & PU_BM_BLCOM)
static INT16 UVC_puBacklightCur    = 3; 		/* ProcessingUnit Backlight Current */
static INT16 UVC_puBacklightDef    = 3; 		/* ProcessingUnit Backlight Default */
static INT16 UVC_puBacklightMin    = 1; 		/* ProcessingUnit Backlight Minimum */
static INT16 UVC_puBacklightMax    = 6; 		/* ProcessingUnit Backlight Maximum */
static INT16 UVC_puBacklightRes    = 0x0001; 	/* ProcessingUnit Backlight Resolution */
#endif

#if (UVC_PU_CONTROL_BM & PU_BM_GAMMA)
static INT16 UVC_puGammaCur    = 10; 			/* ProcessingUnit Gamma Current */
static INT16 UVC_puGammaDef    = 0; 			/* ProcessingUnit Gamma Default */
static INT16 UVC_puGammaMin    = 0; 			/* ProcessingUnit Gamma Minimum */
static INT16 UVC_puGammaMax    = 20; 			/* ProcessingUnit Gamma Maximum */
static INT16 UVC_puGammaRes    = 0x0001; 		/* ProcessingUnit Gamma Resolution */
#endif

static INT8U Mute;
static INT16U VolCur = 0x3000;		/* Volume Current Value */
const INT16U VolMin = 0x1E00;		/* Volume Minimum Value */
const INT16U VolMax = 0x3200;		/* Volume Maximum Value */
const INT16U VolRes = 0x0A00;		/* Volume Resolution */

ALIGN4 static UVC_VIDEO_PROBE_AND_COMMIT_CONTROL UVC_vsVideoProbe =
{
	0x001F,                 // bitfield indicating what fields shall be kept fixed
    0x01,                   // Video format index from a format descriptor
    0x01,                   // Video frame index from a frame descriptor
    //0x000A2C2A,             // Frame intervall in 100 ns units
    0x51615,                 //Frame intervall in 333333 ns units
    0x0000,                 // Key frame rate in key-frame per video-frame units
    0x0000,                 // PFrame rate i PFrame/key frame units
    0x0000,                 // Compression quality control in abstarct units (0..10000)
    0x0000,                 // Window size for average bit rate control
    0x00FF,                 // int. VS interface latency in ms from capture to presentation
  #if JPG_WIDTH==1280 && JPG_HEIGHT==720
  	0x001C2000,             // maximum video frame or codec specific segemet size in bytes 1280*720*2
  #else
    0x00096000,             // maximum video frame or codec specific segemet size in bytes 640*480*2
  #endif
#if UVC_11
    0x0000200,
#else
    0x0000400,             // max. bytes the device can transmit/receive in single payload transfer
#endif
#if (UVC_VERSION ==  0x0110)
    0x00000000,             // device clock frequency in Hz for sepcified format
    0x00,                   // bitfield control
    0x00,                   // preferred payload format version for specifide bFormatIndex
    0x00,                   // minimum payload format version for specifide bFormatIndex
    0x00                    // maximum payload format version for specifide bFormatIndex
#endif
};

#define SELECT_PIN_BUF_SIZE	59

ALIGN4 static INT8U UVC_suSelectedInputPinMin[SELECT_PIN_BUF_SIZE] =    /* SelectorUnit   selcted input pin */
{
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00
};

ALIGN4 static INT8U UVC_suSelectedInputPinMax[SELECT_PIN_BUF_SIZE] =    /* SelectorUnit   selcted input pin */
{
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF
};

ALIGN4 static INT8U UVC_suSelectedInputPinData[SELECT_PIN_BUF_SIZE] =    /* SelectorUnit   selcted input pin */
{
	0x01, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00
};

ALIGN4 static INT8U UVC_suSelectedInputPinDef[SELECT_PIN_BUF_SIZE] =    /* SelectorUnit   selcted input pin */
{
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80, 0x80,
	0x80, 0x80, 0x80
};

ALIGN4 static INT8U uvc_img_probe_commit[11] =
{
	0x00, 0x01, 0x00, 0x00,
	0x00, 0x01, 0x00, 0x00,
	0x00, 0x01, 0x00
};

ALIGN4 static INT8U UVC_vcData3[3] =
{
	0x00, 0x00, 0x00
};

ALIGN4 static INT8U UVC_vcData6[6] =
{
	0x00, 0x00, 0x00, 0x00,
	0x00, 0x00
};

ALIGN4 INT8U EP0Buf[EP0_BUF_SIZE] = {0};

ISO_FRAME_TRANSFER_DONE iso_video_frame_done = NULL;
ISO_FRAME_TRANSFER_DONE iso_audio_frame_done = NULL;
ISO_FRAME_TRANSFER_DONE iso_key_done = NULL;
static INT8U isep5flush = 0;
static INT8U isep7flush = 0;
GET_SET_INTERFACE get_set_interface = NULL;
/******************************************************
	USB descriptor tables for diagnostic test
******************************************************/

extern void drv_l2_usbd_state_ctl_ep0_in(INT32U event);
/******************************************************
    Local functions
******************************************************/
/******************************************************
    UAC API functions
******************************************************/
static INT32U UAC_GetCur(USBD_SETUP_MSG* setupmsg)
{
	//INT8U indexL = setupmsg->wIndex & 0x00FF;
	//INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(valueH)
	{
		case AUDIO_MUTE_CONTROL:
			ctl_ctlblk.dataptr = &Mute;
			ctl_ctlblk.datacnt = 1;
			break;

		case AUDIO_VOLUME_CONTROL:
			ctl_ctlblk.dataptr = (INT8U*)&VolCur;
			ctl_ctlblk.datacnt = 2;
			break;

		default:
			return 0;
	}


	return 1;
}

static INT32U UAC_GetMin(USBD_SETUP_MSG* setupmsg)
{
	//INT8U indexL = setupmsg->wIndex & 0x00FF;
	//INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(valueH)
	{
		case AUDIO_VOLUME_CONTROL:
			ctl_ctlblk.dataptr = (INT8U*)&VolMin;
			ctl_ctlblk.datacnt = 2;
			return 1;

		default:
			break;
	}
	return 0;
}

static INT32U UAC_GetMax(USBD_SETUP_MSG* setupmsg)
{
	//INT8U indexL = setupmsg->wIndex & 0x00FF;
	//INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(valueH)
	{
		case AUDIO_VOLUME_CONTROL:
			ctl_ctlblk.dataptr = (INT8U*)&VolMax;
			ctl_ctlblk.datacnt = 2;
			return 1;

		default:
			break;
	}

	return 0;
}

static INT32U UAC_GetRes(USBD_SETUP_MSG* setupmsg)
{
	//INT8U indexL = setupmsg->wIndex & 0x00FF;
	//INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(valueH)
	{
		case AUDIO_VOLUME_CONTROL:
			ctl_ctlblk.dataptr = (INT8U*)&VolRes;
			ctl_ctlblk.datacnt = 2;
			return 1;

		default:
			break;
	}

	return 0;
}

static INT32U UAC_SetCur(USBD_SETUP_MSG* setupmsg)
{
 	//INT8U indexL = setupmsg->wIndex & 0x00FF;
	//INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(valueH)
	{
		case AUDIO_MUTE_CONTROL:
			Mute = EP0Buf[0];
			break;

		case AUDIO_VOLUME_CONTROL:
			VolCur = (EP0Buf[1] << 8) | EP0Buf[0];
			break;
	}

	return 1;
}
/******************************************************
    UVC API functions
******************************************************/
static INT32U UVC_GetCur(USBD_SETUP_MSG* setupmsg)
{
	INT8U indexL = setupmsg->wIndex & 0x00FF;
	INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(indexL)
	{                       // select the Interface
		case USB_UVC_VCIF_NUM:                                 // Video Control Interface
	  		switch (indexH)
	  		{                   // select the Entity
	   			case 0:                                            // interface control requests
	      			switch (valueH)
	      			{               // select the  selector control
	        			case VC_VIDEO_POWER_MODE_CONTROL:	/* wValue = 0x0100, wIndex = 0x0000, return 1 byte */
	          				ctl_ctlblk.dataptr = (INT8U *)&UVC_PowerMode;
	          				ctl_ctlblk.datacnt = 1;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	        			case VC_REQUEST_ERROR_CODE_CONTROL:	/* wValue = 0x0200, wIndex = 0x0000, return 1 byte */
	          				EP0Buf[0] = UVC_ErrorCode;
	          				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
	          				ctl_ctlblk.datacnt = 1;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
					}
	      			break;

				case 1:                                            // InputTerminal (camera)    see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case 0x02:	/* wValue = 0x0200, wIndex = 0x0100, return 1 byte */
	        				EP0Buf[0] = 0x08;
	        				ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 1;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x04:	/* wValue = 0x0400, wIndex = 0x0100, return 4 bytes */
	        				EP0Buf[0] = 0x71;
	        				EP0Buf[1] = 0x02;
	        				EP0Buf[2] = 0x00;
	        				EP0Buf[3] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 4;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	         				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 2:                                            // InputTerminal (composite) see usbdesc.c
	      			switch (valueH)
	      			{              // select the  selector control
	        			default:
	          			UVC_ErrorCode = INVALID_CONTROL_ERR;
	        			break;
	      			}
	      			break;

	    		case 3:                                            // OutputTerminal            see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	      				case 0x02:	/* wValue = 0x0200, wIndex = 0x0300, return 2 bytes */
	      					EP0Buf[0] = 0x00;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 2;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x03:	/* wValue = 0x0300, wIndex = 0x0300, return 2 bytes */
	      					EP0Buf[0] = 0x40;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 2;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x06:	/* wValue = 0x0600, wIndex = 0x0300, return 2 bytes */
	      					EP0Buf[0] = 0x00;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 2;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x07:	/* wValue = 0x0700, wIndex = 0x0300, return 2 bytes */
	      					EP0Buf[0] = 0x40;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 2;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x08:	/* wValue = 0x0800, wIndex = 0x0300, return 2 bytes */
	      					EP0Buf[0] = 0x10;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 2;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x09:	/* wValue = 0x0900, wIndex = 0x0300, return 2 bytes */
	      					EP0Buf[0] = 0x64;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 2;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x0A:	/* wValue = 0x0A00, wIndex = 0x0300, return 2 bytes */
	      					EP0Buf[0] = 0x50;
	      					EP0Buf[1] = 0x14;
	      					ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 2;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x0B:	/* wValue = 0x0B00, wIndex = 0x0300, return 1 byte */
	      					EP0Buf[0] = 0x01;
	      					ctl_ctlblk.dataptr = (INT8U *)EP0Buf;
	          				ctl_ctlblk.datacnt = 1;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 4:                                            // SelectorUnit              see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case SU_INPUT_SELECT_CONTROL:
							memcpy(EP0Buf, UVC_suSelectedInputPinData, SELECT_PIN_BUF_SIZE);
	          				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
	          				ctl_ctlblk.datacnt = 1;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	        			case 0x02:	/* wValue = 0x0200, wIndex = 0x0400, return 6 byte */
	        				ctl_ctlblk.dataptr = (INT8U *)&UVC_vcData6[0];
	          				ctl_ctlblk.datacnt = 6;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x03:	/* wValue = 0x0300, wIndex = 0x0400, return 3 byte */
	        				ctl_ctlblk.dataptr = (INT8U *)&UVC_vcData3[0];
	          				ctl_ctlblk.datacnt = 3;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 5:                                            // ProcessingUnit            see usbdesc.c
	      			switch (valueH)
	      			{
#if (UVC_PU_CONTROL_BM & PU_BM_BRIGHTNESS)
	        			case PU_BRIGHTNESS_CONTROL:
							ctl_ctlblk.dataptr = (INT8U *)&UVC_puBrightnessCur;
							ctl_ctlblk.datacnt = 2;
							UVC_ErrorCode = NO_ERROR_ERR;
							break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_HUE)
						case PU_HUE_CONTROL:
							ctl_ctlblk.dataptr = (INT8U *)&UVC_puHueCur;
							ctl_ctlblk.datacnt = 2;
							UVC_ErrorCode = NO_ERROR_ERR;
							break;
#endif
#if (UVC_PU_CONTROL_BM & PU_CONTRAST_CONTROL)
						case PU_CONTRAST_CONTROL:
							ctl_ctlblk.dataptr = (INT8U *)&UVC_puContrastCur;
							ctl_ctlblk.datacnt = 2;
							UVC_ErrorCode = NO_ERROR_ERR;	
							break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SATURATION)
						case PU_SATURATION_CONTROL:
							ctl_ctlblk.dataptr = (INT8U *)&UVC_puSaturationCur;
							ctl_ctlblk.datacnt = 2;
							UVC_ErrorCode = NO_ERROR_ERR;	
							break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SHARPNESS)
						case PU_SHARPNESS_CONTROL:
							ctl_ctlblk.dataptr = (INT8U *)&UVC_puSharpnessCur;
							ctl_ctlblk.datacnt = 2;
							UVC_ErrorCode = NO_ERROR_ERR;	
							break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_BLCOM)
						case PU_BACKLIGHT_COMPENSATION_CONTROL:
							ctl_ctlblk.dataptr = (INT8U *)&UVC_puBacklightCur;
							ctl_ctlblk.datacnt = 2;
							UVC_ErrorCode = NO_ERROR_ERR;	
							break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_GAMMA)
						case PU_GAMMA_CONTROL:
							ctl_ctlblk.dataptr = (INT8U *)&UVC_puGammaCur;
							ctl_ctlblk.datacnt = 2;
							UVC_ErrorCode = NO_ERROR_ERR;	
							break;
#endif				
						default:
							UVC_ErrorCode = INVALID_CONTROL_ERR;
						break;
	      			}
	      			break;

	    		default:
	      			UVC_ErrorCode = INVALID_UNIT_ERR;
	      			break;
	  		}
	  		break;

		case USB_UVC_VSIF_NUM:                                 // Video Streaming Interface
	    	switch (valueH)
	    	{               // select the  selector control
	        	case VS_PROBE_CONTROL :	/* wValue = 0x0100, wIndex = 0x0001, return 26 bytes */
	        	case VS_COMMIT_CONTROL:	/* wValue = 0x0200, wIndex = 0x0001, return 26 bytes */
	          		ctl_ctlblk.dataptr = (INT8U *)&UVC_vsVideoProbe;
	          		ctl_ctlblk.datacnt = sizeof(UVC_VIDEO_PROBE_AND_COMMIT_CONTROL);
	          		UVC_ErrorCode = NO_ERROR_ERR;
	          		break;

	        	case VS_STILL_PROBE_CONTROL:	/* wValue = 0x0300, wIndex = 0x0001, return 11 bytes */
	        		ctl_ctlblk.dataptr = (INT8U *)&uvc_img_probe_commit;
	        		ctl_ctlblk.datacnt = 11;
	        		UVC_ErrorCode = NO_ERROR_ERR;
	        		break;

	        	default:
	          		UVC_ErrorCode = INVALID_CONTROL_ERR;
	          		break;
	      	}
	  		break;

		default:
	  		UVC_ErrorCode = UNKNOWN_ERR;
	 		break;
	}

	if (UVC_ErrorCode == NO_ERROR_ERR)
    	return 1;                                         // we handled the request
  	else
    	return 0;
}

static INT32U UVC_GetDef(USBD_SETUP_MSG* setupmsg)
{
	INT8U indexL = setupmsg->wIndex & 0x00FF;
	INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(indexL)
	{                       // select the Interface
		case USB_UVC_VCIF_NUM:                                 // Video Control Interface
			switch (indexH)
		  	{                   // select the Entity
		  		case 1:                                            // InputTerminal (camera)    see usbdesc.c
		      		switch (valueH)
		      		{               // select the  selector control
		      			case 0x04:	/* wValue = 0x0400, wIndex = 0x0100, return 4 bytes */
		      				EP0Buf[0] = 0x71;
		      				EP0Buf[1] = 0x02;
		      				EP0Buf[2] = 0x00;
		      				EP0Buf[3] = 0x00;
		      				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		      				ctl_ctlblk.datacnt = 4;
		      				UVC_ErrorCode = NO_ERROR_ERR;
		      				break;

		        		default:
		          			UVC_ErrorCode = INVALID_CONTROL_ERR;
		          			break;
					}
		      		break;

		    	case 2:                                            // InputTerminal (composite) see usbdesc.c
		      		switch (valueH)
		      		{               // select the  selector control
		        		default:
		          		UVC_ErrorCode = INVALID_CONTROL_ERR;
		          		break;
		      		}
		      		break;

		    	case 3:                                            // OutputTerminal            see usbdesc.c
		      		switch (valueH)
		      		{               // select the  selector control
		        		case 0x02:	/* wValue = 0x0200, wIndex = 0x0300, return 2 bytes */
		        			EP0Buf[0] = 0x7F;
		      				EP0Buf[1] = 0xF2;
		      				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		      				ctl_ctlblk.datacnt = 2;
		      				UVC_ErrorCode = NO_ERROR_ERR;
		        			break;

		        		case 0x03:	/* wValue = 0x0300, wIndex = 0x0300, return 2 bytes */
		        			EP0Buf[0] = 0x40;
		      				EP0Buf[1] = 0x00;
		      				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		      				ctl_ctlblk.datacnt = 2;
		      				UVC_ErrorCode = NO_ERROR_ERR;
		        			break;

						case 0x05:	/* wValue = 0x0500, wIndex = 0x0300, return 1 byte */
		        			EP0Buf[0] = 0x01;
		        			ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		      				ctl_ctlblk.datacnt = 1;
		        			UVC_ErrorCode = NO_ERROR_ERR;
		        			break;

						case 0x06:	/* wValue = 0x0600, wIndex = 0x0300, return 2 bytes */
		        			EP0Buf[0] = 0x00;
		      				EP0Buf[1] = 0x00;
		      				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		      				ctl_ctlblk.datacnt = 2;
		      				UVC_ErrorCode = NO_ERROR_ERR;
		        			break;

		        		case 0x07:	/* wValue = 0x0700, wIndex = 0x0300, return 2 bytes */
		        			EP0Buf[0] = 0x40;
		      				EP0Buf[1] = 0x00;
		      				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		      				ctl_ctlblk.datacnt = 2;
		      				UVC_ErrorCode = NO_ERROR_ERR;
		        			break;

		        		case 0x08:	/* wValue = 0x0800, wIndex = 0x0300, return 2 bytes */
		        			EP0Buf[0] = 0x10;
		      				EP0Buf[1] = 0x00;
		      				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		      				ctl_ctlblk.datacnt = 2;
		      				UVC_ErrorCode = NO_ERROR_ERR;
		        			break;

		        		case 0x09:	/* wValue = 0x0900, wIndex = 0x0300, return 2 bytes */
		        			EP0Buf[0] = 0x64;
		      				EP0Buf[1] = 0x00;
		      				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		      				ctl_ctlblk.datacnt = 2;
		      				UVC_ErrorCode = NO_ERROR_ERR;
		        			break;

		        		case 0x0A:	/* wValue = 0x0A00, wIndex = 0x0300, return 2 bytes */
		        			EP0Buf[0] = 0x50;
		      				EP0Buf[1] = 0x14;
		      				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		      				ctl_ctlblk.datacnt = 2;
		      				UVC_ErrorCode = NO_ERROR_ERR;
		        			break;

		        		default:
		          			UVC_ErrorCode = INVALID_CONTROL_ERR;
		          			break;
		      		}
		     		break;

		    	case 4:                                            // SelectorUnit              see usbdesc.c
		      		switch (valueH)
		      		{               // select the  selector control
		        		case SU_INPUT_SELECT_CONTROL:	/* wValue = 0x0100, wIndex = 0x0400, return 59 bytes */
		          			memcpy(EP0Buf, UVC_suSelectedInputPinDef, SELECT_PIN_BUF_SIZE);
		          			ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
		          			ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
		          			UVC_ErrorCode = NO_ERROR_ERR;
		          			break;

		          		case 0x02:	/* wValue = 0x0200, wIndex = 0x0400, return 6 bytes */
	        				EP0Buf[0] = 0x80;
	        				EP0Buf[1] = 0x80;
	        				EP0Buf[2] = 0x80;
	        				EP0Buf[3] = 0x80;
	        				EP0Buf[4] = 0x80;
	        				EP0Buf[5] = 0x80;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
	        				ctl_ctlblk.datacnt = 6;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x03:	/* wValue = 0x0300, wIndex = 0x0400, return 3 bytes */
	        				EP0Buf[0] = 0x80;
	        				EP0Buf[1] = 0x80;
	        				EP0Buf[2] = 0x80;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
	        				ctl_ctlblk.datacnt = 3;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x04:	/* wValue = 0x0400, wIndex = 0x0400, return 59 bytes */
		          			ctl_ctlblk.dataptr = (INT8U *)&UVC_suSelectedInputPinDef;
		          			ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
		          			UVC_ErrorCode = NO_ERROR_ERR;
		          			break;

		          		case 0x05:	/* wValue = 0x0500, wIndex = 0x0400, return 59 bytes */
		          			ctl_ctlblk.dataptr = (INT8U *)&UVC_suSelectedInputPinDef;
		          			ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
		          			UVC_ErrorCode = NO_ERROR_ERR;
		          			break;
		      		}
		      		break;

		    	case 5:                                            // ProcessingUnit            see usbdesc.c
		      		switch (valueH)
		      		{
#if (UVC_PU_CONTROL_BM & PU_BM_BRIGHTNESS)
		        		case PU_BRIGHTNESS_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puBrightnessDef;
      			        	ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_HUE)              				
              			case PU_HUE_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puHueDef;
      			        	ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_CONTRAST_CONTROL)
              			case PU_CONTRAST_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puContrastDef;
      			        	ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;	
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SATURATION)
              			case PU_SATURATION_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puSaturationDef;
      			        	ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;	
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SHARPNESS)
              			case PU_SHARPNESS_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puSharpnessDef;
      			        	ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;		
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_BLCOM)
              			case PU_BACKLIGHT_COMPENSATION_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puBacklightDef;
      			        	ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;		
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_GAMMA)
              			case PU_GAMMA_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puGammaDef;
      			        	ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;		
              				break;
#endif
		      		}
		      		break;

		    	default:
		      		UVC_ErrorCode = INVALID_UNIT_ERR;
		      		break;
		 	 }
		 	 break;

		case USB_UVC_VSIF_NUM:                                 // Video Streaming Interface
			switch (valueH)
			{               // select the  selector control
		    	default:
		    	UVC_ErrorCode = INVALID_CONTROL_ERR;
		    	break;
		    }
		  	break;

		default:
		  UVC_ErrorCode = UNKNOWN_ERR;
		  break;
	}

	if (UVC_ErrorCode == NO_ERROR_ERR)
    	return 1;                                         // we handled the request
  	else
    	return 0;                                        // if not handled we stall it
}

static INT32U UVC_GetInfo(USBD_SETUP_MSG* setupmsg)
{
	INT8U indexL = setupmsg->wIndex & 0x00FF;
	INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(indexL)
	{ 								                      // select the Interface
  	case USB_UVC_VCIF_NUM:                                 // Video Control Interface
		switch (indexH)
      	{                   // select the Entity
			case 0:                                            // interface control requests
				switch (valueH)
				{               // select the  selector control
					case VC_VIDEO_POWER_MODE_CONTROL:
					  	EP0Buf[0] = (SUPPORTS_GET | SUPPORTS_SET);
					  	ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
					  	UVC_ErrorCode = NO_ERROR_ERR;
					  	break;

					case VC_REQUEST_ERROR_CODE_CONTROL:
						EP0Buf[0] = (SUPPORTS_GET);
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
					  	UVC_ErrorCode = NO_ERROR_ERR;
					  	break;

					default:
					  	UVC_ErrorCode = INVALID_CONTROL_ERR;
					  	break;
				}
				break;

			case 1:                                            // InputTerminal (camera)    see usbdesc.c
				switch (valueH)
			  	{               // select the  selector control
				    case 0x04:	/* wValue = 0x0400, wIndex = 0x0100, return 1 byte */
				    	EP0Buf[0] = 0x0F;
				    	ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
				    	UVC_ErrorCode = NO_ERROR_ERR;
				    	break;

				    default:
				    	UVC_ErrorCode = INVALID_CONTROL_ERR;
				      	break;
			  	}
				break;

			case 2:                                            // InputTerminal (composite) see usbdesc.c
				switch (valueH)
				{               // select the  selector control
					default:
				  		UVC_ErrorCode = INVALID_CONTROL_ERR;
				  		break;
				}
				break;

			case 3:                                            // OutputTerminal            see usbdesc.c
				switch (valueH)
				{               // select the  selector control
					case 0x02:	/* wValue = 0x0200, wIndex = 0x0300, return 1 byte */
						EP0Buf[0] = 0x03;
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
						break;

					case 0x03:	/* wValue = 0x0300, wIndex = 0x0300, return 1 byte */
						EP0Buf[0] = 0x03;
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
						break;

					case 0x05:	/* wValue = 0x0500, wIndex = 0x0300, return 1 byte */
						EP0Buf[0] = 0x03;
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
						break;

					case 0x06:	/* wValue = 0x0600, wIndex = 0x0300, return 1 byte */
						EP0Buf[0] = 0x03;
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
						break;

					case 0x07:	/* wValue = 0x0700, wIndex = 0x0300, return 1 byte */
						EP0Buf[0] = 0x03;
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
						break;

					case 0x08:	/* wValue = 0x0800, wIndex = 0x0300, return 1 byte */
						EP0Buf[0] = 0x03;
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
						break;

					case 0x09:	/* wValue = 0x0900, wIndex = 0x0300, return 1 byte */
						EP0Buf[0] = 0x03;
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
						break;

					case 0x0A:	/* wValue = 0x0A00, wIndex = 0x0300, return 1 byte */
						EP0Buf[0] = 0x0F;
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
						break;

					default:
				  		UVC_ErrorCode = INVALID_CONTROL_ERR;
				 		break;
				}
				break;

			case 0x04:                                            // SelectorUnit              see usbdesc.c
				switch (valueH)
				{               // select the  selector control
					case SU_INPUT_SELECT_CONTROL:
				  		EP0Buf[0] = (SUPPORTS_GET | SUPPORTS_SET);
				  		ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
				  		UVC_ErrorCode = NO_ERROR_ERR;
				 	 	break;

				 	case 0x02:	/* wValue = 0x0200, wIndex = 0x0400, return 1 byte */
				 		EP0Buf[0] = 0x03;
				 		ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
				 		break;

				 	case 0x03:	/* wValue = 0x0300, wIndex = 0x0400, return 1 byte */
				 		EP0Buf[0] = 0x03;
				 		ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
				 		break;

				 	case 0x04:	/* wValue = 0x0400, wIndex = 0x0400, return 1 byte */
				 		EP0Buf[0] = 0x03;
				 		ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
				 		break;

				 	case 0x05:	/* wValue = 0x0500, wIndex = 0x0400, return 1 byte */
				 		EP0Buf[0] = 0x03;
				 		ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
				 		break;

				}
			  	break;
			case 5:                                            // ProcessingUnit            see usbdesc.c
				switch (valueH)
				{
#if (UVC_PU_CONTROL_BM & PU_BM_BRIGHTNESS)
					case PU_BRIGHTNESS_CONTROL:
						EP0Buf[0] = (SUPPORTS_GET | SUPPORTS_SET);
						ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
      			        ctl_ctlblk.datacnt = 1;
						UVC_ErrorCode = NO_ERROR_ERR;
						break;
#endif
				}
			  	break;

			default:
				UVC_ErrorCode = INVALID_UNIT_ERR;
			  	break;
		}
		break;

    case USB_UVC_VSIF_NUM:                                 // Video Streaming Interface
		switch (valueH)
		{               // select the  selector control
			default:
		  		UVC_ErrorCode = INVALID_CONTROL_ERR;
		  		break;
		}
      	break;

    default:
		UVC_ErrorCode = UNKNOWN_ERR;
		break;
  }

	if (UVC_ErrorCode == NO_ERROR_ERR)
    	return 1;                                         // we handled the request
  	else
    	return 0;                                        // if not handled we stall it
}

static INT32U UVC_GetLen(USBD_SETUP_MSG* setupmsg)
{
	INT8U indexL = setupmsg->wIndex & 0x00FF;
	INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(indexL)
	{                       // select the Interface
		case USB_UVC_VCIF_NUM:                                 // Video Control Interface
	  		switch (indexH)
	  		{                   // select the Entity
	    		case 0x04:
	    			switch (valueH)
	      			{
	      				case 0x01:	/* wValue = 0x0100, wIndex = 0x0400, return 2 bytes */
	      					EP0Buf[0] = 0x3B;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	      					UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x02:	/* wValue = 0x0200, wIndex = 0x0400, return 2 bytes */
	      					EP0Buf[0] = 0x06;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	      					UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x03:	/* wValue = 0x0300, wIndex = 0x0400, return 2 bytes */
	      					EP0Buf[0] = 0x03;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	      					UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x04:	/* wValue = 0x0400, wIndex = 0x0400, return 2 bytes */
	      					EP0Buf[0] = 0x3B;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	      					UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x05:	/* wValue = 0x0500, wIndex = 0x0400, return 2 bytes */
	      					EP0Buf[0] = 0x3B;
	      					EP0Buf[1] = 0x00;
	      					ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	      					UVC_ErrorCode = NO_ERROR_ERR;
	      					break;

	      				case 0x06:	/* wValue = 0x0600, wIndex = 0x0400, stall EP0 */
	      					UVC_ErrorCode = INVALID_REQUEST_ERR;
	      					break;

	      				default:
	      					UVC_ErrorCode = INVALID_CONTROL_ERR;
	      					break;
	      			}
	    			break;

	    		case 5:                                            // ProcessingUnit            see usbdesc.c
	      			switch (valueH)
	      			{
#if (UVC_PU_CONTROL_BM & PU_BM_BRIGHTNESS)
	        			case PU_BRIGHTNESS_CONTROL:
	          				UVC_ErrorCode = INVALID_REQUEST_ERR;
	          				break;
#endif

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		default:
	    			UVC_ErrorCode = INVALID_UNIT_ERR;
	      			break;
	  		}
	  		break;

		case USB_UVC_VSIF_NUM:                                 // Video Streaming Interface
			switch (valueH)
	    	{               // select the  selector control
	   		 	default:
	  		      	UVC_ErrorCode = INVALID_CONTROL_ERR;
	  	        	break;
			}
			break;

		default:
	 		UVC_ErrorCode = UNKNOWN_ERR;
	  		break;
	}

	if (UVC_ErrorCode == NO_ERROR_ERR)
    	return 1;                                         // we handled the request
  	else
    	return 0;                                        // if not handled we stall it
}

static INT32U UVC_GetMax(USBD_SETUP_MSG* setupmsg)
{
	INT8U indexL = setupmsg->wIndex & 0x00FF;
	INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(indexL)
	{                       // select the Interface
		case USB_UVC_VCIF_NUM:                                 // Video Control Interface
	  		switch (indexH)
	  		{                   // select the Entity
	   			case 1:                                            // InputTerminal (camera)    see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case 0x04:		/* wValue = 0x0400, wIndex = 0x0100, return 4 bytes */
	        				EP0Buf[0] = 0x88;
	        				EP0Buf[1] = 0x13;
	        				EP0Buf[2] = 0x00;
	        				EP0Buf[3] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 4;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 2:                                            // InputTerminal (composite) see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 3:                                            // OutputTerminal            see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case 0x02:	/* wValue = 0x0200, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x7F;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x03:	/* wValue = 0x0300, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x7F;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x05:	/* wValue = 0x0500, wIndex = 0x0300, return 1 byte */
	        				EP0Buf[0] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 1;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x06:	/* wValue = 0x0600, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x80;
	        				EP0Buf[1] = 0x3E;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x07:	/* wValue = 0x0700, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0xFF;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x08:	/* wValue = 0x0800, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x0F;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x09:	/* wValue = 0x0900, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0xF4;
	        				EP0Buf[1] = 0x01;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x0A:	/* wValue = 0x0A00, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x64;
	        				EP0Buf[1] = 0x19;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 4:                                            // SelectorUnit              see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case SU_INPUT_SELECT_CONTROL:	/* wValue = 0x0100, wIndex = 0x0400, return 59 bytes */
							memcpy(EP0Buf, UVC_suSelectedInputPinMax, SELECT_PIN_BUF_SIZE);
	          				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	        			case 0x02:	/* wValue = 0x0200, wIndex = 0x0400, return 6 bytes */
	        				EP0Buf[0] = 0xFF;
	        				EP0Buf[1] = 0xFF;
	        				EP0Buf[2] = 0xFF;
	        				EP0Buf[3] = 0xFF;
	        				EP0Buf[4] = 0xFF;
	        				EP0Buf[5] = 0xFF;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 6;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x03:	/* wValue = 0x0300, wIndex = 0x0400, return 3 bytes */
	        				EP0Buf[0] = 0xFF;
	        				EP0Buf[1] = 0xFF;
	        				EP0Buf[2] = 0xFF;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = 3;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x04:	/* wValue = 0x0400, wIndex = 0x0400, return 59 bytes */
	        				memcpy(EP0Buf, UVC_suSelectedInputPinMax, SELECT_PIN_BUF_SIZE);
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x05:	/* wValue = 0x0500, wIndex = 0x0400, return 59 bytes */
	        				memcpy(EP0Buf, UVC_suSelectedInputPinMax, SELECT_PIN_BUF_SIZE);
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
							ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 5:
	      			switch (valueH)
	      			{
#if (UVC_PU_CONTROL_BM & PU_BM_BRIGHTNESS)
	        			case PU_BRIGHTNESS_CONTROL:
              				ctl_ctlblk.dataptr = (INT8U *)&UVC_puBrightnessMax;
              				ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_HUE)              				
              			case PU_HUE_CONTROL:
              				ctl_ctlblk.dataptr = (INT8U *)&UVC_puHueMax;
              				ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_CONTRAST_CONTROL)
              			case PU_CONTRAST_CONTROL:
              				ctl_ctlblk.dataptr = (INT8U *)&UVC_puContrastMax;
              				ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SATURATION)
              			case PU_SATURATION_CONTROL:
              				ctl_ctlblk.dataptr = (INT8U *)&UVC_puSaturationMax;
              				ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SHARPNESS)
              			case PU_SHARPNESS_CONTROL:
              				ctl_ctlblk.dataptr = (INT8U *)&UVC_puSharpnessMax;
              				ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;	
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_BLCOM)
              			case PU_BACKLIGHT_COMPENSATION_CONTROL:
              				ctl_ctlblk.dataptr = (INT8U *)&UVC_puBacklightMax;
              				ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;	
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_GAMMA)
              			case PU_GAMMA_CONTROL:
              				ctl_ctlblk.dataptr = (INT8U *)&UVC_puGammaMax;
              				ctl_ctlblk.datacnt = 2;
              				UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
            			default:
              				UVC_ErrorCode = INVALID_CONTROL_ERR;
              				break;
	      			}
	      			break;

	    		default:
	      			UVC_ErrorCode = INVALID_UNIT_ERR;
	      			break;
			} // end SetupPacket.wIndex.WB.H
	  		break;

	     case USB_UVC_VSIF_NUM:                                 // Video Streaming Interface
	    	switch (valueH)
	    	{               // select the  selector control
	        	case VS_PROBE_CONTROL :	/* wValue = 0x0100, wIndex = 0x0001, return 26 bytes */
	        	case VS_COMMIT_CONTROL:	/* wValue = 0x0200, wIndex = 0x0001, return 26 bytes */
	          		ctl_ctlblk.dataptr = (INT8U *)&UVC_vsVideoProbe;
	          		ctl_ctlblk.datacnt = sizeof(UVC_VIDEO_PROBE_AND_COMMIT_CONTROL);
	          		UVC_ErrorCode = NO_ERROR_ERR;
	          		break;

	        	case 0x03:	/* wValue = 0x0300, wIndex = 0x0001, return 11 bytes */
	        		ctl_ctlblk.dataptr = (INT8U *)&uvc_img_probe_commit;
	        		ctl_ctlblk.datacnt = 11;
	        		UVC_ErrorCode = NO_ERROR_ERR;
	        		break;

	        	default:
	          		UVC_ErrorCode = INVALID_CONTROL_ERR;
	          		break;
	      	}
	  		break;

		default:
			UVC_ErrorCode = UNKNOWN_ERR;
		  	break;
	}

	if (UVC_ErrorCode == NO_ERROR_ERR)
    	return 1;                                         // we handled the request
  	else
    	return 0;                                        // if not handled we stall it

}

static INT32U UVC_GetMin(USBD_SETUP_MSG* setupmsg)
{
	INT8U indexL = setupmsg->wIndex & 0x00FF;
	INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(indexL)
	{                       // select the Interface
		case USB_UVC_VCIF_NUM:                                 // Video Control Interface
			switch (indexH)
			{                   // select the Entity
				case 1:                                            // InputTerminal (camera)    see usbdesc.c
					switch (valueH)
					{               // select the  selector control
			    		case 0x04:		/* wValue = 0x0400, wIndex = 0x0100, return 4 bytes */
			    			EP0Buf[0] = 0x01;
			    			EP0Buf[1] = 0x00;
			    			EP0Buf[2] = 0x00;
			    			EP0Buf[3] = 0x00;
			    			ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 4;
			    			UVC_ErrorCode = NO_ERROR_ERR;
			    			break;

			    		default:
			      			UVC_ErrorCode = INVALID_CONTROL_ERR;
			      			break;
			  		}
			  		break;

	    		case 2:            									// InputTerminal (composite) see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			default:
	          			UVC_ErrorCode = INVALID_CONTROL_ERR;
	          			break;
	      			}
	      			break;

	    		case 3:                                            // OutputTerminal            see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case 0x02:  /* wValue = 0x0200, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x81;
	        				EP0Buf[1] = 0xFF;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x03:	/* wValue = 0x0300, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x00;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x05:	/* wValue = 0x0500, wIndex = 0x0300, return 1 byte */
	        				EP0Buf[0] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 1;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

						case 0x06:	/* wValue = 0x0600, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x80;
	        				EP0Buf[1] = 0xC1;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x07:	/* wValue = 0x0700, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x00;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x08:	/* wValue = 0x0800, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x00;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x09:	/* wValue = 0x0900, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x10;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

						case 0x0A:	/* wValue = 0x0A00, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0xF0;
	        				EP0Buf[1] = 0x0A;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 4:                                            // SelectorUnit              see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case SU_INPUT_SELECT_CONTROL:	/* wValue = 0x0100, wIndex = 0x0400, return 59 bytes */
	          				memcpy(EP0Buf, UVC_suSelectedInputPinMin, SELECT_PIN_BUF_SIZE);
	          				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	          			case 0x02:	/* wValue = 0x0200, wIndex = 0x0400, return 6 bytes */
	        				EP0Buf[0] = 0x00;
	        				EP0Buf[1] = 0x00;
	        				EP0Buf[2] = 0x00;
	        				EP0Buf[3] = 0x00;
	        				EP0Buf[4] = 0x00;
	        				EP0Buf[5] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 6;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x03:	/* wValue = 0x0300, wIndex = 0x0400, return 3 bytes */
	        				EP0Buf[0] = 0x00;
	        				EP0Buf[1] = 0x00;
	        				EP0Buf[2] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 3;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

						case 0x04:	/* wValue = 0x0400, wIndex = 0x0400, return 59 bytes */
	        				memcpy(EP0Buf, UVC_suSelectedInputPinMin, SELECT_PIN_BUF_SIZE);
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

						case 0x05:	/* wValue = 0x0500, wIndex = 0x0400, return 59 bytes */
	        				memcpy(EP0Buf, UVC_suSelectedInputPinMin, SELECT_PIN_BUF_SIZE);
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 5:
	      			switch (valueH)
	      			{
#if (UVC_PU_CONTROL_BM & PU_BM_BRIGHTNESS)
	        			case PU_BRIGHTNESS_CONTROL:
		            		ctl_ctlblk.dataptr = (INT8U *)&UVC_puBrightnessMin;
		              		ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
		              		break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_HUE)
		              	case PU_HUE_CONTROL:
		            		ctl_ctlblk.dataptr = (INT8U *)&UVC_puHueMin;
		              		ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
		              		break;
#endif
#if (UVC_PU_CONTROL_BM & PU_CONTRAST_CONTROL)
		              	case PU_CONTRAST_CONTROL:
		            		ctl_ctlblk.dataptr = (INT8U *)&UVC_puContrastMin;
		              		ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
		              		break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SATURATION)
		              	case PU_SATURATION_CONTROL:
		            		ctl_ctlblk.dataptr = (INT8U *)&UVC_puSaturationMin;
		              		ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
		              		break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SHARPNESS)
		              	case PU_SHARPNESS_CONTROL:
		            		ctl_ctlblk.dataptr = (INT8U *)&UVC_puSharpnessMin;
		              		ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
		              		break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_BLCOM)
		              	case PU_BACKLIGHT_COMPENSATION_CONTROL:
		            		ctl_ctlblk.dataptr = (INT8U *)&UVC_puBacklightMin;
		              		ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
		              		break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_GAMMA)
		              	case PU_GAMMA_CONTROL:
		            		ctl_ctlblk.dataptr = (INT8U *)&UVC_puGammaMin;
		              		ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
		              		break;
#endif					
		            	default:
		              		UVC_ErrorCode = INVALID_CONTROL_ERR;
		              		break;
	      			}
	      			break;

	    		default:
	      			UVC_ErrorCode = INVALID_UNIT_ERR;
	      			break;
	  		} // end SetupPacket.wIndex.WB.H
	  		break;

	    case USB_UVC_VSIF_NUM:                                 // Video Streaming Interface
	    	switch (valueH)
	    	{               // select the  selector control
	        	case VS_PROBE_CONTROL :	/* wValue = 0x0100, wIndex = 0x0001, return 26 bytes */
	        	case VS_COMMIT_CONTROL:	/* wValue = 0x0200, wIndex = 0x0001, return 26 bytes */
	          		ctl_ctlblk.dataptr = (INT8U *)&UVC_vsVideoProbe;
	          		ctl_ctlblk.datacnt = sizeof(UVC_VIDEO_PROBE_AND_COMMIT_CONTROL);
	          		UVC_ErrorCode = NO_ERROR_ERR;
	          		break;

	        	case 0x03:	/* wValue = 0x0300, wIndex = 0x0001, return 11 bytes */
	        		ctl_ctlblk.dataptr = (INT8U *)&uvc_img_probe_commit;
	        		ctl_ctlblk.datacnt = 11;
	        		UVC_ErrorCode = NO_ERROR_ERR;
	        		break;

	        	default:
	          		UVC_ErrorCode = INVALID_CONTROL_ERR;
	          		break;
	      	}
	  		break;

		default:
	  		UVC_ErrorCode = UNKNOWN_ERR;
	  		break;
	}

	if(UVC_ErrorCode == NO_ERROR_ERR)
    	return 1;                                         // we handled the request
  	else
    	return 0;                                        // if not handled we stall it
}

static INT32U UVC_GetRes(USBD_SETUP_MSG* setupmsg)
{
	INT8U indexL = setupmsg->wIndex & 0x00FF;
	INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;

	switch(indexL)
	{                       // select the Interface
		case USB_UVC_VCIF_NUM:                                 // Video Control Interface
			switch (indexH)
			{                   // select the Entity
	    		case 1:                                            // InputTerminal (camera)    see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	      				case 0x04:	/* wValue = 0x0400, wIndex = 0x0100, return 4 bytes */
	      					EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				EP0Buf[2] = 0x00;
	        				EP0Buf[3] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 4;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 2:                                            // InputTerminal (composite) see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 3:                                            // OutputTerminal            see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case 0x02:	/* wValue = 0x0200, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x03:	/* wValue = 0x0300, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x05:	/* wValue = 0x0500, wIndex = 0x0300, return 1 byte */
	        				EP0Buf[0] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 1;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x06:	/* wValue = 0x0600, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x07:	/* wValue = 0x0700, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x08:	/* wValue = 0x0800, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x09:	/* wValue = 0x0900, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x0A:	/* wValue = 0x0A00, wIndex = 0x0300, return 2 bytes */
	        				EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
              				ctl_ctlblk.datacnt = 2;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	     			 break;

	    		case 4:                                            // SelectorUnit              see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case SU_INPUT_SELECT_CONTROL:	/* wValue = 0x0100, wIndex = 0x0400, return 59 bytes */
	          				memcpy(EP0Buf, UVC_suSelectedInputPinData, SELECT_PIN_BUF_SIZE);
	          				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
	          				ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	        			case 0x02:	/* wValue = 0x0200, wIndex = 0x0400, return 6 bytes */
	        				EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				EP0Buf[2] = 0x00;
	        				EP0Buf[3] = 0x00;
	        				EP0Buf[4] = 0x00;
	        				EP0Buf[5] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
	          				ctl_ctlblk.datacnt = 6;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x03:	/* wValue = 0x0300, wIndex = 0x0400, return 3 bytes */
	        				EP0Buf[0] = 0x01;
	        				EP0Buf[1] = 0x00;
	        				EP0Buf[2] = 0x00;
	        				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
	          				ctl_ctlblk.datacnt = 3;
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x04:	/* wValue = 0x0400, wIndex = 0x0400, return 59 bytes */
	          				memcpy(EP0Buf, UVC_suSelectedInputPinData, SELECT_PIN_BUF_SIZE);
	          				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
	          				ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	        			case 0x05:	/* wValue = 0x0500, wIndex = 0x0400, return 59 bytes */
	        				memcpy(EP0Buf, UVC_suSelectedInputPinData, SELECT_PIN_BUF_SIZE);
	          				ctl_ctlblk.dataptr = (INT8U *)&EP0Buf;
	          				ctl_ctlblk.datacnt = SELECT_PIN_BUF_SIZE;
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 5:
	      			switch (valueH)
	      			{
#if (UVC_PU_CONTROL_BM & PU_BM_BRIGHTNESS)
	        			case PU_BRIGHTNESS_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puBrightnessRes;
              				ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_HUE)
              			case PU_HUE_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puHueRes;
              				ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_CONTRAST_CONTROL)
              			case PU_CONTRAST_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puContrastRes;
              				ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SATURATION)
              			case PU_SATURATION_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puSaturationRes;
              				ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SHARPNESS)
              			case PU_SHARPNESS_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puSharpnessRes;
              				ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_BLCOM)
              			case PU_BACKLIGHT_COMPENSATION_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puBacklightRes;
              				ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_GAMMA)
              			case PU_GAMMA_CONTROL:
            				ctl_ctlblk.dataptr = (INT8U *)&UVC_puGammaRes;
              				ctl_ctlblk.datacnt = 2;
		              		UVC_ErrorCode = NO_ERROR_ERR;
              				break;
#endif					
 			        	default:
            				UVC_ErrorCode = INVALID_CONTROL_ERR;
              				break;
	      			}
	      			break;

	    		default:
	      			UVC_ErrorCode = INVALID_UNIT_ERR;
	      			break;
	  		}
	  		break;

		case USB_UVC_VSIF_NUM:                                 // Video Streaming Interface
	    	switch (valueH)
	    	{               // select the  selector control
	        	default:
	          		UVC_ErrorCode = INVALID_CONTROL_ERR;
	          		break;
	      	}
	  		break;

		default:
	  		UVC_ErrorCode = UNKNOWN_ERR;
	  		break;
	}

	if (UVC_ErrorCode == NO_ERROR_ERR)
    	return 1;                                         // we handled the request
  	else
    	return 0;
}

static INT32U UVC_SetCur(USBD_SETUP_MSG* setupmsg)
{
 	INT8U indexL = setupmsg->wIndex & 0x00FF;
	INT8U indexH = (setupmsg->wIndex & 0xFF00) >> 8;
	//INT8U valueL = setupmsg->wValue & 0x00FF;
	INT8U valueH = (setupmsg->wValue & 0xFF00) >> 8;
	INT16 wTemp;

	switch(indexL)
  	{                       // select the Interface
		case USB_UVC_VCIF_NUM:                                 // Video Control Interface
	  		switch (indexH)
	  		{                   // select the Entity
	    		case 0:                                            // interface control requests
	      			switch (valueH)
	      			{               // select the  selector control
	        			case VC_VIDEO_POWER_MODE_CONTROL:
	          				UVC_PowerMode = EP0Buf[0];
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      		break;

	    		case 1:                                            // InputTerminal (camera)         see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			} // end SetupPacket.wValue.WB.H
	      			break;

	    		case 2:                                            // InputTerminal (composite)      see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 3:                                            // OutputTerminal                 see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	     			break;

	    		case 4:                                            // SelectorUnit                   see usbdesc.c
	      			switch (valueH)
	      			{               // select the  selector control
	        			case SU_INPUT_SELECT_CONTROL:
	          				UVC_suSelectedInputPinData[0] = EP0Buf[0];
	          				UVC_ErrorCode = NO_ERROR_ERR;
	          				break;

	        			case 0x02:	/* wValue = 0x0200, wIndex = 0x0400, get 6 bytes */
	        				memcpy((void *)&UVC_vcData6, (const void *)EP0Buf, 6);
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			case 0x03:	/* wValue = 0x0300, wIndex = 0x0400, get 3 bytes */
	        				memcpy((void *)&UVC_vcData3, (const void *)EP0Buf, 3);
	        				UVC_ErrorCode = NO_ERROR_ERR;
	        				break;

	        			default:
	          				UVC_ErrorCode = INVALID_CONTROL_ERR;
	          				break;
	      			}
	      			break;

	    		case 5:                                            // ProcessingUnit                 see usbdesc.c
	      			switch (valueH)
	      			{
#if (UVC_PU_CONTROL_BM & PU_BM_BRIGHTNESS)
	        			case PU_BRIGHTNESS_CONTROL:                    // Brightness is supported   see usbdesc.c
			            	//wTemp = *((__packed INT16 *)EP0Buf);
			          		wTemp = EP0Buf[0] << 8 | EP0Buf[1];
			              	if ((wTemp >= UVC_puBrightnessMin) &&        // check the value to set
			                	  (wTemp <= UVC_puBrightnessMax))
			          		{   
			                	UVC_puBrightnessCur = wTemp; 
			                	UVC_ErrorCode = NO_ERROR_ERR;
			              	}
			              	else
			              	{
			                	UVC_ErrorCode = OUT_OF_RANGE_ERR;
			              	}
			              	break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_HUE)
		              	case PU_HUE_CONTROL:                    // Hue is supported   see usbdesc.c
			            	//wTemp = *((__packed INT16 *)EP0Buf);
		              		wTemp = EP0Buf[0] << 8 | EP0Buf[1];
			              	if ((wTemp >= UVC_puHueMin) &&        // check the value to set
			                	  (wTemp <= UVC_puHueMax))
			          		{   
			                	UVC_puHueCur = wTemp; 
			                	UVC_ErrorCode = NO_ERROR_ERR;
			              	}
			              	else
			              	{
			                	UVC_ErrorCode = OUT_OF_RANGE_ERR;
			              	}
			              	break;
#endif
#if (UVC_PU_CONTROL_BM & PU_CONTRAST_CONTROL)
			            case PU_CONTRAST_CONTROL:                    // Contrast is supported   see usbdesc.c
			            	//wTemp = *((__packed INT16 *)EP0Buf);
			            	wTemp = EP0Buf[0] << 8 | EP0Buf[1];
			              	if ((wTemp >= UVC_puContrastMin) &&        // check the value to set
			                	  (wTemp <= UVC_puContrastMax))
			          		{   
			                	UVC_puContrastCur = wTemp; 
			                	UVC_ErrorCode = NO_ERROR_ERR;
			              	}
			              	else
			              	{
			                	UVC_ErrorCode = OUT_OF_RANGE_ERR;
			              	}
			              	break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SATURATION)
			          	case PU_SATURATION_CONTROL:                    // Saturation is supported   see usbdesc.c
			            	//wTemp = *((__packed INT16 *)EP0Buf);
			          		wTemp = EP0Buf[0] << 8 | EP0Buf[1];
			              	if ((wTemp >= UVC_puSaturationMin) &&        // check the value to set
			                	  (wTemp <= UVC_puSaturationMax))
			          		{   
			                	UVC_puSaturationCur = wTemp; 
			                	UVC_ErrorCode = NO_ERROR_ERR;
			              	}
			              	else
			              	{
			                	UVC_ErrorCode = OUT_OF_RANGE_ERR;
			              	}
			              	break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_SHARPNESS)
		            	case PU_SHARPNESS_CONTROL:                   	// Sharpness is supported   see usbdesc.c
			            	//wTemp = *((__packed INT16 *)EP0Buf);
		            		wTemp = EP0Buf[0] << 8 | EP0Buf[1];
			              	if ((wTemp >= UVC_puSharpnessMin) &&		// check the value to set
			                	  (wTemp <= UVC_puSharpnessMax))
			          		{   
			                	UVC_puSharpnessCur = wTemp; 
			                	UVC_ErrorCode = NO_ERROR_ERR;
			              	}
			              	else
			              	{
			                	UVC_ErrorCode = OUT_OF_RANGE_ERR;
			              	}
			              	break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_BLCOM)
			             case PU_BACKLIGHT_COMPENSATION_CONTROL:        // Backlight is supported   see usbdesc.c
			            	//wTemp = *((__packed INT16 *)EP0Buf);
			            	 wTemp = EP0Buf[0] << 8 | EP0Buf[1];
			              	if ((wTemp >= UVC_puBacklightMin) &&        // check the value to set
			                	  (wTemp <= UVC_puBacklightMax))
			          		{   
			                	UVC_puSharpnessCur = wTemp; 
			                	UVC_ErrorCode = NO_ERROR_ERR;
			              	}
			              	else
			              	{
			                	UVC_ErrorCode = OUT_OF_RANGE_ERR;
			              	}
			              	break;
#endif
#if (UVC_PU_CONTROL_BM & PU_BM_GAMMA)
			             case PU_GAMMA_CONTROL:        					// Gamma is supported   see usbdesc.c
			            	//wTemp = *((__packed INT16 *)EP0Buf);
			            	 wTemp = EP0Buf[0] << 8 | EP0Buf[1];
			              	if ((wTemp >= UVC_puGammaMin) &&        	// check the value to set
			                	  (wTemp <= UVC_puGammaMax))
			          		{   
			                	UVC_puGammaCur = wTemp; 
			                	UVC_ErrorCode = NO_ERROR_ERR;
			              	}
			              	else
			              	{
			                	UVC_ErrorCode = OUT_OF_RANGE_ERR;
			              	}
			              	break;
#endif	
		            	default:
		              		UVC_ErrorCode = INVALID_CONTROL_ERR;
		              		break;
	     			} // end SetupPacket.wValue.WB.H
	      			break;

	    		default:
	      			UVC_ErrorCode = INVALID_UNIT_ERR;
	      			break;
			}
	  		break;

		case USB_UVC_VSIF_NUM:                                 // Video Streaming Interface
	    	switch (valueH)
	    	{               // select the  selector control
	        	case VS_PROBE_CONTROL :	/* wValue = 0x0100, wIndex = 0x0001, return 26 bytes */
	        	case VS_COMMIT_CONTROL: /* wValue = 0x0200, wIndex = 0x0001, return 26 bytes */
	          		memcpy((void *)&UVC_vsVideoProbe, (const void *)EP0Buf, sizeof(UVC_VIDEO_PROBE_AND_COMMIT_CONTROL));
	          		UVC_ErrorCode = NO_ERROR_ERR;
	          		if( UVC_vsVideoProbe.bFormatIndex != 1 || UVC_vsVideoProbe.bFrameIndex != 1 || UVC_vsVideoProbe.dwFrameInterval != 0x51615 )
	            		UVC_ErrorCode = INVALID_CONTROL_ERR;

#if JPG_WIDTH == 1280 && JPG_HEIGHT == 720
					UVC_vsVideoProbe.dwMaxVideoFrameSize = 0x001C2000;	
#else
					UVC_vsVideoProbe.dwMaxVideoFrameSize = 0x00096000;
#endif
					if(drv_l1_usbd_get_cur_speed() == USB_SPEED_11)
						UVC_vsVideoProbe.dwMaxPayloadTransferSize = USB11_ISO_EP5_MAX_SIZE;
					else
	        			UVC_vsVideoProbe.dwMaxPayloadTransferSize = USB20_ISO_EP5_MAX_SIZE;
	          		break;

	        	case VS_STILL_PROBE_CONTROL:	/* wValue = 0x0300, wIndex = 0x0001, return 11 bytes */
	        		memcpy((void *)&uvc_img_probe_commit, (const void *)EP0Buf, 11);
	        		uvc_img_probe_commit[2] = 0x00;
#if JPG_WIDTH == 1280 && JPG_HEIGHT == 720					
					uvc_img_probe_commit[3] = 0x00;
					uvc_img_probe_commit[4] = 0x20;
					uvc_img_probe_commit[5] = 0x1C;
					uvc_img_probe_commit[6] = 0x00;
#else
					uvc_img_probe_commit[3] = 0x00;
					uvc_img_probe_commit[4] = 0x60;
					uvc_img_probe_commit[5] = 0x09;
					uvc_img_probe_commit[6] = 0x00;
#endif
	        		uvc_img_probe_commit[7] = 0x40;
	        		uvc_img_probe_commit[8] = 0x00;
	        		uvc_img_probe_commit[9] = 0x00;
	        		uvc_img_probe_commit[10] = 0x00;
	        		UVC_ErrorCode = NO_ERROR_ERR;
	        		break;

	        	case VS_STILL_COMMIT_CONTROL: /* wValue = 0x0400, wIndex = 0x0001, return 11 bytes */
	        		memcpy((void *)&uvc_img_probe_commit, (const void *)EP0Buf, 11);
	        		uvc_img_probe_commit[2] = 0x00;
#if JPG_WIDTH == 1280 && JPG_HEIGHT == 720					
					uvc_img_probe_commit[3] = 0x00;
					uvc_img_probe_commit[4] = 0x20;
					uvc_img_probe_commit[5] = 0x1C;
					uvc_img_probe_commit[6] = 0x00;
#else
					uvc_img_probe_commit[3] = 0x00;
					uvc_img_probe_commit[4] = 0x60;
					uvc_img_probe_commit[5] = 0x09;
					uvc_img_probe_commit[6] = 0x00;
#endif
	        		uvc_img_probe_commit[7] = 0x40;
	        		uvc_img_probe_commit[8] = 0x00;
	        		uvc_img_probe_commit[9] = 0x00;
	        		uvc_img_probe_commit[10] = 0x00;

	        		UVC_ErrorCode = NO_ERROR_ERR;
	        		break;

	        	default:
	          		UVC_ErrorCode = INVALID_CONTROL_ERR;
	          		break;
	      	}
			break;

		default:
	  		UVC_ErrorCode = UNKNOWN_ERR;
	  		break;
	}

	if (UVC_ErrorCode == NO_ERROR_ERR)
    	return 1;                                     // we handled the request
  	else
    	return 0;                                     // if not handled we stall it
}

void drv_l2_usbd_register_uvc_frame_done_cbk(ISO_FRAME_TRANSFER_DONE cbk)
{
	iso_video_frame_done = cbk;
}

void drv_l2_usbd_register_uac_frame_done_cbk(ISO_FRAME_TRANSFER_DONE cbk)
{
	iso_audio_frame_done = cbk;
}

void drv_l2_usbd_register_uvc_key_done_cbk(ISO_FRAME_TRANSFER_DONE cbk)
{
	iso_key_done = cbk;	
}

void drv_l2_usbd_register_set_interface_cbk(GET_SET_INTERFACE cbk)
{
	get_set_interface = cbk;
}

/******************************************************
        State function declaration
    	drv_l2_usbd_uvc_state_iso_in()
    	drv_l2_usbd_uvc_state_iso_out()
    	drv_l2_usbd_uvc_state_int_in()
    	drv_l2_usbd_uvc_state_int_out()
******************************************************/
static void drv_l2_usbd_uvc_state_iso_in(INT32U event)
{
    switch(event)
    {
        case USBD_ISO_IN_EP5_PKT_CLEAR_EVENT:
        	if(iso_video_frame_done != NULL)
        	{
        		iso_video_frame_done();
        	}
        	break;
         case USBD_ISO_IN_EP7_PKT_CLEAR_EVENT:
         	if(iso_audio_frame_done != NULL)
        	{
        		iso_audio_frame_done();
        	}
        	break;
        default:
            DBG_PRINT("L2: ISO IN, unknown event %d!\r\n", event);
            break;
    }
}

static void drv_l2_usbd_uvc_state_iso_out(INT32U event)
{
    switch(event)
    {
        case USBD_ISO_OUT_PKT_READY_EVENT:
            /* Start ISO OUT DMA */
            //drv_l1_usbd_dma_iso_out((void*)isobuf, isooutcnt);
            break;
        case USBD_ISO_OUT_DMA_DONE_EVENT:
            DBG_PRINT("L2: ISO OUT, DMA done,data is in isobuf!\r\n");
            break;
        default:
            //DBG_PRINT("L2DIAGLOG: ISO OUT, unknown event %d!\r\n", event);
            break;
    }
}

static void drv_l2_usbd_uvc_state_int_in(INT32U event)
{
	DBG_PRINT("UVC INT IN state, event = %d\r\n", event);
    switch(event)
    {
        case USBD_INT_IN_NACK_EVENT:
            /* A Interrupt IN token happened but device send NACK */
            //DBG_PRINT("L2DIAGLOG: INT IN, Device sent NACK!!!\r\n");
            break;
        case USBD_INT_IN_PACKET_CLEAR_EVENT:
            //DBG_PRINT("L2DIAGLOG: INT IN, Packet clear!!!\r\n");
            drv_l1_usbd_disable_int_in_packet_clear_interrupt();
            break;
        case USBD_INT_EP3_IN_PACKET_CLEAR_EVENT:
        	//DBG_PRINT("L2DIAGLOG: EP3 INT IN, Packet clear!!!\r\n");
        	if(iso_key_done != NULL)
        	{
        		iso_key_done();
        	}
        	break;
        case USBD_INT_EP4_IN_PACKET_CLEAR_EVENT:
        	//DBG_PRINT("L2DIAGLOG: EP4 INT IN, Packet clear!!!\r\n");
        	break;
        case USBD_INT_EP6_IN_PACKET_CLEAR_EVENT:
        	//DBG_PRINT("L2DIAGLOG: EP6 INT IN, Packet clear!!!\r\n");
        	break;
        default:
            //DBG_PRINT("USBDL2DIAG: INT IN, unknown event %d!\r\n", event);
            break;
    }
}

static void drv_l2_usbd_uvc_state_int_out(INT32U event)
{
    /* Hardware not support now, TBD */
}

INT32U drv_l2_usbd_uvc_check_ep5_flush(void)
{
	if(isep5flush)
	{
		isep5flush = 0;
		return 1;
	}
	return 0;
}

INT32U drv_l2_usbd_uvc_check_ep7_flush(void)
{
	if(isep7flush)
	{
		isep7flush = 0;
		return 1;
	}
	return 0;
}


void drv_l2_usbd_misc_uvc_handle(INT32U event)
{
	static INT32U isoep5altnum = 0;
	static INT32U isoep7altnum = 0;

	switch(event)
    {
        case USBD_MISC_RESET_EVENT:
            drv_l2_usbd_ctl_reset();
            DBG_PRINT("Received RST!!\r\n");
            break;
        case USBD_MISC_SET_CONF_EVENT:
            DBG_PRINT("Get set config!\r\n");
            break;
        case USBD_MISC_SET_INTERFACE_EVENT:
        	DBG_PRINT("SET INTERFACE EP5[%d][%d] EP7[%d][%d]!\r\n", isoep5altnum, drv_l1_usbd_iso_ep5_get_alt_intf_num(), isoep7altnum, drv_l1_usbd_iso_ep7_get_alt_intf_num());

			if(isoep5altnum != 0 && drv_l1_usbd_iso_ep5_get_alt_intf_num() == 0)
			{
				isep5flush = 1;
			}

			if(isoep7altnum != 0 && drv_l1_usbd_iso_ep7_get_alt_intf_num() == 0)
			{
				isep7flush = 1;
			}
			isoep5altnum = drv_l1_usbd_iso_ep5_get_alt_intf_num();
			isoep7altnum = drv_l1_usbd_iso_ep7_get_alt_intf_num();

			if(get_set_interface)
			{
				get_set_interface(isoep5altnum, isoep7altnum);
			}
			break;
        case USBD_MISC_GET_SUSPEND_EVENT:
            DBG_PRINT("Received suspend!\r\n");
            break;
        case USBD_MISC_GET_RESUM_EVENT:
            DBG_PRINT("Received resume!\r\n");
            break;
        case USBD_MISC_MSDC_INSERT_EVENT:
            DBG_PRINT("L2: USBD_MISC_MSDC_INSERT_EVENT!\r\n");
            break;
        case USBD_MISC_SET_ADDRESS_EVENT:
            DBG_PRINT("Reveived Set address = 0x%x in %s\r\n", rUDC_ADDR & 0x7F, drv_l1_usbd_get_cur_speed()==USB_SPEED_11?"full speed":"high speed");
            if(drv_l1_usbd_get_cur_speed() == USB_SPEED_11)
            {
            	USB_UVC_MJPEG_ConfigDescriptor[212 + 0x0A] = (INT8U)(USB11_ISO_EP5_MAX_SIZE&0x00FF);
				USB_UVC_MJPEG_ConfigDescriptor[213 + 0x0A] = (USB11_ISO_EP5_MAX_SIZE&0xFF00) >> 8;
			}
			else
			{
				USB_UVC_MJPEG_ConfigDescriptor[212 + 0x0A] = (INT8U)(USB20_ISO_EP5_MAX_SIZE&0x00FF);
				USB_UVC_MJPEG_ConfigDescriptor[213 + 0x0A] = (USB20_ISO_EP5_MAX_SIZE&0xFF00) >> 8;
			}
            break;
        default:
            break;
    }
}

/****************************************************************
    UVC ISO IN API
****************************************************************/
/* Following area is for GP17 diagnostic test code, including USB L1 and L2 of control transfer */
static void _uvc_process_setup_request(void)
{
    INT32U  cnt;
    INT8U   bmdir, bmtype, bmrecipient, destype, desindex;

    GetSetupBMReqType(ctl_ctlblk.setupmsg.bmRequestType, bmdir, bmtype, bmrecipient);
    GetDescriptorbywVlaue(ctl_ctlblk.setupmsg.wValue, destype, desindex);

    //DBG_PRINT("USBDL2: bmRequestType, bmdir %d, bmtype %d, bmrecipient %d, destype %d, desindex %d\r\n", bmdir, bmtype,
    //           bmrecipient, destype, desindex);

    if(bmtype == USBD_REQ_STANDARD)
    {
        /* Get descriptor standard request */
        if(ctl_ctlblk.setupmsg.bRequest == USBD_STDREQ_GET_DESCRIPTOR)
        {
            //DBG_PRINT("USBDL2: USBD_STDREQ_GET_DESCRIPTOR, destype %d \r\n", destype);
            switch(destype)
            {
                case USBD_DES_DEVICE_TYPE:  /* device descriptor */
                    ctl_ctlblk.dataptr = ctl_ctlblk.dev_desptr;
                    ctl_ctlblk.datacnt = ctl_ctlblk.dev_desptr[0];
                    break;

                case USBD_DES_CONFIG_TYPE:
                case USBD_DES_OTHER_SPEED_CONFIGURATION_TYPE:
                    ctl_ctlblk.dataptr = ctl_ctlblk.config_desptr;
                    ctl_ctlblk.datacnt = ctl_ctlblk.dataptr[2] + (ctl_ctlblk.dataptr[3] << 8);
                    /* Normal / Other speed */
                    if(destype == USBD_DES_CONFIG_TYPE)
                    {
                    	ctl_ctlblk.config_desptr[1] = USBD_DES_CONFIG_TYPE;
                    } else if(destype == USBD_DES_OTHER_SPEED_CONFIGURATION_TYPE)
                    {
                        ctl_ctlblk.config_desptr[1] = USBD_DES_OTHER_SPEED_CONFIGURATION_TYPE;
                    }
                    break;

                case USBD_DES_STRING_TYPE:
                    switch(desindex)
                    {
                        case 0:
                            ctl_ctlblk.dataptr = ctl_ctlblk.str0_desptr;
                            break;
                        case 1:
                            ctl_ctlblk.dataptr = ctl_ctlblk.str1_desptr;
                            break;
                        case 2:
                            ctl_ctlblk.dataptr = ctl_ctlblk.str2_desptr;
                            break;
                        case 3:
                            ctl_ctlblk.dataptr = ctl_ctlblk.str3_desptr;
                            break;
                        case 4:
                            ctl_ctlblk.dataptr = ctl_ctlblk.str4_desptr;
                            break;
                        case 5:
                            ctl_ctlblk.dataptr = ctl_ctlblk.str5_desptr;
                            break;
                        default:
                            break;
                    }
                    ctl_ctlblk.datacnt = ctl_ctlblk.dataptr[0];
                    break;

                case USBD_DES_DEVICE_QUALIFIER_TYPE:
                    ctl_ctlblk.dataptr = ctl_ctlblk.dev_qualifier_desptr;
                    ctl_ctlblk.datacnt = ctl_ctlblk.dataptr[0];
                    break;
                default:
                    /* un-support descriptor here, return stall and back to previous function */
                    drv_l1_usbd_send_ep0_stall();
                    return;
            }
                /* write and send descriptor data */
                _check_ep0_data_send_zero();
                cnt = drv_l1_usbd_send_ep0_in(ctl_ctlblk.dataptr, ctl_ctlblk.datacnt);
                ctl_ctlblk.datacnt -= cnt;
                ctl_ctlblk.dataptr += cnt;
        }
    }
    else if(bmtype == USBD_REQ_CLASS)
    {
    	INT32U ret = 0;
    	//DBG_PRINT("UVC class request got, req = 0x%x\r\n", ctl_ctlblk.setupmsg.bRequest);
        if(bmdir == USBD_DATA_DIR_D2H)
        {
	        INT8U indexL = ctl_ctlblk.setupmsg.wIndex & 0x00FF;
	        if(indexL == USB_UVC_VCIF_NUM || indexL == USB_UVC_VSIF_NUM)
	        {
		        /* For UVC device, support GET_CUR, GET_MIN, GET_MAX, GET_RES, GET_LEN, GET_INFO, GET_DEF class request*/
		        switch(ctl_ctlblk.setupmsg.bRequest)
		        {
		            case GET_CUR:
		            	ret = UVC_GetCur(&ctl_ctlblk.setupmsg);
		            	break;

		            case GET_DEF:
		            	ret = UVC_GetDef(&ctl_ctlblk.setupmsg);
		            	break;

		            case GET_INFO:
		            	ret = UVC_GetInfo(&ctl_ctlblk.setupmsg);
		            	break;

		            case GET_LEN:
		            	ret = UVC_GetLen(&ctl_ctlblk.setupmsg);
		            	break;

		            case GET_MAX:
		            	ret = UVC_GetMax(&ctl_ctlblk.setupmsg);
		            	break;

		            case GET_MIN:
		            	ret = UVC_GetMin(&ctl_ctlblk.setupmsg);
		            	break;

		            case GET_RES:
		            	ret = UVC_GetRes(&ctl_ctlblk.setupmsg);
		            	break;

		            default:
		            	ret = 0;
		                break;
		        }
	    	}
	    	else if(indexL == USB_UAC_VCIF_NUM || indexL == USB_UAC_VSIF_NUM)
	    	{
	    		/* UAC class request */
	    		switch(ctl_ctlblk.setupmsg.bRequest)
		        {
		            case GET_CUR:
		            	ret = UAC_GetCur(&ctl_ctlblk.setupmsg);
		            	break;

		            case GET_MIN:
		            	ret = UAC_GetMin(&ctl_ctlblk.setupmsg);
		            	break;

		            case GET_MAX:
		            	ret = UAC_GetMax(&ctl_ctlblk.setupmsg);
		            	break;

		            case GET_RES:
		            	ret = UAC_GetRes(&ctl_ctlblk.setupmsg);
		            	break;

		            default:
		            	ret = 0;
		                break;
		        }
	    	}

	        if(ret == 0)
	        {
	        	/* send EP0 stall back to host */
	        	drv_l1_usbd_send_ep0_stall();
	    	}
	    	else
	    	{
				/* write and send descriptor data */
				_check_ep0_data_send_zero();
				cnt = drv_l1_usbd_send_ep0_in(ctl_ctlblk.dataptr, ctl_ctlblk.datacnt);
				ctl_ctlblk.datacnt -= cnt;
				ctl_ctlblk.dataptr += cnt;
			}
		}
		else if(bmdir == USBD_DATA_DIR_H2D)
		{
			INT8U indexL = ctl_ctlblk.setupmsg.wIndex & 0x00FF;

			if(indexL == USB_UVC_VCIF_NUM || indexL == USB_UVC_VSIF_NUM
				|| indexL == USB_UAC_VCIF_NUM || indexL == USB_UAC_VSIF_NUM)
			{
				switch(ctl_ctlblk.setupmsg.bRequest)
				{
					case SET_CUR:
						/* Get data cnt and enable EP0 OUT to get data */
						ctl_ctlblk.datacnt = ctl_ctlblk.setupmsg.wLength;
						drv_l1_usbd_enable_receive_ep0_out();
						break;

					default:
						break;
				}
			}
		}
    }
    else if(bmtype == USBD_REQ_VENDOR)
    {
    }
    else
    {
        /* To do, USBD_REQ_RESERVED */
    }
}

void drv_l2_usbd_state_ctl_ep0_uvc_uc_out(INT32U event)
{
	drv_l1_usbd_disable_ep0();
    switch(event)
    {
        //INT32U len;

        case USBD_EP0_OUT_READY_EVENT:
           	if(ctl_ctlblk.datacnt == 0)
            {
            	//DBG_PRINT("Check receive data OUT\r\n");
            	if(drv_l2_usbd_check_ep0_state_stage(USBD_DATA_DIR_OUT_HANDLE))
            	{
               		ctl_ctlblk.dataptr = NULL;
            		/* after getting OUT data ,send EP0 IN NULL to finish state stage */
            		drv_l1_usbd_send_ep0_in(NULL, 0);
                	//DBG_PRINT(" State stage, OUT\r\n");
                	return;
            	}
            }
            else
            {
            	//DBG_PRINT("USBD_EP_OUT_READY_EVENT, datacnt = %d\r\n", ctl_ctlblk.datacnt);
            	if(ctl_ctlblk.datacnt != drv_l1_usbd_get_ep0_out_cnt())
            	{
            		DBG_PRINT("Error, out cnt[%d] does not match EP0 request[%d]\r\n", drv_l1_usbd_get_ep0_out_cnt(), ctl_ctlblk.datacnt);
            	}
        		/* process UVC set cur class request */
        		if(ctl_ctlblk.setupmsg.bRequest == SET_CUR)
        		{
        			INT8U indexL = ctl_ctlblk.setupmsg.wIndex & 0x00FF;

        			memset(EP0Buf, 0, EP0_BUF_SIZE);
        			drv_l1_usbd_get_ep0_out_data((void*)EP0Buf, drv_l1_usbd_get_ep0_out_cnt());

        			if(indexL == USB_UVC_VCIF_NUM || indexL == USB_UVC_VSIF_NUM)
        			{
        				UVC_SetCur(&ctl_ctlblk.setupmsg);	/* UVC class set request */
        			} else if(indexL == USB_UAC_VCIF_NUM || indexL == USB_UAC_VSIF_NUM)
        			{
        				UAC_SetCur(&ctl_ctlblk.setupmsg);	/* UAC class set request */
        			}
        		}
        		ctl_ctlblk.datacnt = 0;
        		/* send NULL IN for status stage */
        		drv_l1_usbd_send_ep0_in(NULL, 0);
        		//DBG_PRINT("send null in\r\n");
        	}

            break;
        default:
            break;
    }
}

void drv_l2_usbd_state_ctl_ep0_uvc_setup(INT32U event)
{
    /* In a control transfer, get SETUP 8 bytes data and process it */
    switch(event)
    {
        case USBD_SETUP_CMD_EVENT:
            drv_l2_usbd_get_setup_token();
            _uvc_process_setup_request();
            break;

        default:
            break;
    }
}

void drv_l1_usbd_uvc_set_still_image(INT32U flag)
{
	if(flag)
		rEP5HDCTRL |= MASK_USBD_EP5_HDCTL_FRAMESTILL;
	else
		rEP5HDCTRL &= ~MASK_USBD_EP5_HDCTL_FRAMESTILL;
}

INT32S drv_l1_usbd_uvc_init(void)
{
	/* Enable USB PHY and switch to device mode */
	drv_l1_usbd_phy_clk_on();

 	DBG_PRINT("usbd uvc layer 1 init, rSYS_CTRL_NEW =0x%x\r\n", rSYS_CTRL_NEW);
 	
	/* software reset UDC */
	rUDCCS_UDC |= MASK_USBD_UDC_CS_SOFTRST;

	/* Wait for soft reset done */
	while(rUDCCS_UDC & MASK_USBD_UDC_CS_SOFTRST);

	/* 0x3b0[0] cowork with 0x3b4[2] = 1  */
	rUDLC_SET1 |= MASK_USBD_UDLC_SET1_DISC_AUTO_DPDMPD;

	/* Set soft disconnect */
	rUDLC_SET0 |= MASK_USBD_UDLC_SET0_SOFT_DISCONNECT;

	rUDLC_SET0 |= MASK_USBD_UDLC_SET0_PWR_SUSPEND_N;

	/* disable all USB IRQs first */
	rUDC_IRQ_ENABLE = 0;

	rUDLC_SET2 = 0x01;//disable ep3, ep1s is normal priority

	rUDLC_SET0 |= (MASK_USBD_UDLC_SET0_DISCONNECT_SUSPEND_EN | MASK_USBD_UDLC_SET0_CPU_WAKE_UP_EN | MASK_USBD_UDLC_SET0_PWR_SUSPEND_N);//0x35;
	/* Self power */
	rUDLC_SET1 |= MASK_USBD_UDLC_SET1_SELF_POWER;

	/* Set USB device speed */
	if(l1_usbspeed == USB_SPEED_20)
	{
		rUDLC_SET1 &= ~MASK_USBD_UDLC_SET1_FORCE_FULLSP;
	}
	else if(l1_usbspeed == USB_SPEED_11)
	{
		rUDLC_SET1 |= MASK_USBD_UDLC_SET1_FORCE_FULLSP;
	}

	/* clear EP0_DOUT_VLD, free buffer */
	rEP0_CTRL = MASK_USBD_EP0_CS_CLE_EP0_OUT_VLD;

	rUDC_STALL_CTRL	|= (MASK_USBD_UDLC_STL_CLREP0STL | MASK_USBD_UDLC_STL_CLREP1STL | MASK_USBD_UDLC_STL_CLREP2STL); //clear all end points stall

	/* reset EP0_FIFO data cnt */
	rEP0_CNTR = 0;

	// reset both EP12_PIPO and EP1S_FIFO
	rEP12_CTRL |= MASK_USBD_EP12_C_RESET_PIPO_FIFO;
	rEP1S_CTRL |= MASK_USBD_EP1_SCS_RESET_EP1S_FIFO;

	//Clear flags before enable interrupt
	rUDC_IRQ_FLAG = 0xFFFFFFFF;

	rUDC_IRQ_ENABLE = (MASK_USBD_UDC_IE_FORCE_DISC | MASK_USBD_UDC_IE_FORCE_CONN | MASK_USBD_UDC_IE_DMA | MASK_USBD_UDC_IE_VBUS);

	/* Reset linker layer controller interrupt flag */
	rDLCIF_UDLC = 0xFFFFFFFF;
	rDLCIE_UDLC = 0;

	rDLCIE_UDLC = (MASK_USBD_UDLC_IE_EP0S | MASK_USBD_UDLC_IE_RESET | MASK_USBD_UDLC_IE_SUSPEND | MASK_USBD_UDLC_IE_RESUME | MASK_USBD_UDLC_IE_SCONF);

	//Set bit 0~15 to config vbus debounce
	rUDCCS_UDC |= VBUS_SAMPLE_PERIOD_MASK;

	/* enable EP3 */
	rUDLC_SET2 |= MASK_USBD_UDLC_SET2_USBC_SUPPORT_EP3;

	/* Let EP4 = Interface 0 , EP5 = Interface 1 */
	//rUDC_LCS3 = 0x1e;
	/* Let EP5 in interface number 1 [11:8], EP7 in interface 3 , and EPC don't care [31] manual enable bit */
	rEPINF_SETTING =  (MASK_USBD_EPINF_MANUAL_EN | (0x01 << EP5INF_OFFSET) | (0x03 << EP7INF_OFFSET) );

	/* Enable EP5 */
	rEP5EN = MASK_USBD_EP5_EN;

	/* enable EP5 header packet function */
	//rEP5CTL |= MASK_USBD_EP5_CTL_EN;
	//rEP5HDCTRL |= (MASK_USBD_EP5_HDCTL_FRAMEPT | MASK_USBD_EP5_HDCTL_FRAMESTILL);
	rEP5HDLEN = 12;
//	DBG_PRINT("before 0x14c = 0x%x...\r\n", rEP5HDCTRL);
	//rEP5HDCTRL = 0xb;
	rEP5HDCTRL = 0x3;

	rDVIDEO_REFCLOCK = 4;
	//DBG_PRINT("0x14c = 0x%x...\r\n", rEP5HDCTRL);

	rSTANDARD_REQ_IF = 0xFFFFFFFF;
	rSTANDARD_REQ_IE = MASK_USBD_STDREQ_IE_SET_INTF | MASK_USBD_STDREQ_IE_SET_ADDR;

	/* SET SOFT CON */
	rUDLC_SET0 &= ~MASK_USBD_UDLC_SET0_SOFT_DISCONNECT;
	/* 0x3b0[0] cowork with 0x3b4[2] = 1  */
	rUDLC_SET1 &=~ MASK_USBD_UDLC_SET1_DISC_AUTO_DPDMPD;

	/* Force USB PHY connect to USB bus */
	rUDCCS_UDC &= ~MASK_USBD_UDC_CS_SYS_DISCONNECT;

	DBG_PRINT("driver l1 UVC %s init ok 0x%x!\r\n", l1_usbspeed==USB_SPEED_20?"high speed":"full speed", rEP0_CTRL);
    return STATUS_OK;
}

/*****************************************************
    Diagnostic test un/initialization function
*****************************************************/
INT32S drv_l2_usbd_uvc_init(void)
{
	/* Init control state handler */
    drv_l2_usbd_register_state_handler(USBD_XFER_CONTROL, drv_l2_usbd_state_ctl_ep0_uvc_setup, drv_l2_usbd_state_ctl_ep0_in, drv_l2_usbd_state_ctl_ep0_uvc_uc_out);

    /* register ISO IN/OUT state handler */
    drv_l2_usbd_register_state_handler(USBD_XFER_ISO, NULL, drv_l2_usbd_uvc_state_iso_in, drv_l2_usbd_uvc_state_iso_out);

    /* register INT IN/OUT state handler */
    drv_l2_usbd_register_state_handler(USBD_XFER_INT, NULL, drv_l2_usbd_uvc_state_int_in, drv_l2_usbd_uvc_state_int_out);

	drv_l2_usbd_register_state_handler(USBD_XFER_MISC, drv_l2_usbd_misc_uvc_handle, NULL, NULL);

    DBG_PRINT("drv_l2_usbd_uvc_init ok\r\n");
    return STATUS_OK;
}

void drv_l2_usbd_uvc_uninit(void)
{
	/* nothing to do here */
}
